#include "dblock.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>


#define MOD_SSL
#include "ssl_util_sdbm.h"

#define DB_WRITE_MODE 0664

dblock_t* dblock_open(const char* fname)
{
	dblock_t* me = (dblock_t*)calloc(1, sizeof(dblock_t));
	
    //lwh begin
    if (0 == me) return NULL;
    //lwh end
	me->fname = strdup(fname);	
	{
		DBM* db = dbsm_open(me->fname, O_RDWR|O_CREAT, DB_WRITE_MODE);
		me->db = db;
	}

	return me;
}

void dblock_close(dblock_t*me)
{
	if (me) {
		//DBM* db = (DBM*)me->cursor;
		DBM* db = (DBM*)me->db;
		if (db) dbsm_close(db);	
		free(me->fname);
		me->fname = NULL;
		free(me);
	}
}

int dblock_fetch(dblock_t*me, void* key, int keylen, void** pdata)
{
	int len;
	return dblock_fetch_ex(me, key, keylen, pdata, &len);
}

#define NULLITEM(n)  (n.dptr == 0)

int dblock_fetch_ex(dblock_t*me, void* key, int keylen, void** pdata, int* pdatalen)
{
	int ret = -1;
	DBM* db = (DBM*)me->db;
	dbpair ikey = {(char*)key, keylen};
	dbpair idata = {0};

	idata = dbsm_fetch(db, ikey);
	if (NULLITEM(idata)) {
		ret = EDBL_FIND;
		goto __clean;
	}
	*pdata = (void*)idata.dptr;
	//memcpy(*pdata, idata.dptr, idata.dsize);
	*pdatalen = idata.dsize;

	ret = EDBL_OK;
__clean:
	
	return ret;
}

/*
 * flags to dbsm_store
 */
#define DBLOCK_INSERT      0
#define DBLOCK_REPLACE     1
static int dblock_store(dblock_t*me, void* key, int keylen, void* data, int datalen, int flag)
{
	int ret = -1;
	DBM* db = (DBM*)me->db;
	dbpair ikey = {(char*)key, keylen};
	dbpair idata = {(char*)data, datalen};

	ret = dbsm_store(db, ikey, idata, flag);
	if (ret != 0) {
		//WRITELOG(DebugLog, "dblock store %s failed! [%s %s]", me->fname, strerror(errno), __func__);
		ret = EDBL_STORE;
		goto __clean;
	}

	ret = EDBL_OK;
__clean:
	
	return ret;
}

int dblock_replace(dblock_t*db, void* key, int keylen, void* data, int datalen)
{
	return dblock_store(db, key, keylen, data, datalen, DBLOCK_REPLACE);
}

int dblock_insert(dblock_t*db, void* key, int keylen, void* data, int datalen) 
{
	return dblock_store(db, key, keylen, data, datalen, DBLOCK_INSERT);
}

int dblock_delete(dblock_t*me, void* key, int keylen)
{
	int ret = -1;
	DBM* db = (DBM*)me->db;
	dbpair ikey = {(char*)key, keylen};

	ret = dbsm_delete(db, ikey);
	if (ret != 0) {
		usleep(10*1000);
		ret = dbsm_delete(db, ikey);
	}
	if (ret != 0) {
		//WRITELOG(DebugLog, "dblock delete %s failed! [%d %s %s]", me->fname, errno, strerror(errno), __func__);
		ret = EDBL_STORE;
		goto __clean;
	}

	ret = EDBL_OK;
__clean:

	return ret;
}

int dblock_count(dblock_t*me, int * pcount)
{
	int ret = -1;
	DBM* db = (DBM*)me->db;
	dbpair ikey = {0};
	dbpair idata = {0};
	int count = 0;

	ikey = dbsm_firstkey(db);
	while(!NULLITEM(ikey)) {
		count++;
		ikey = dbsm_nextkey(db);
	}

	*pcount = count;
	ret = EDBL_OK;
__clean:

	return ret;
}


int dblock_opencursor(dblock_t*me)
{
	int ret = -1;
	ret = EDBL_OK;

__clean:
	return EDBL_OK;
}

int dblock_firstkey(dblock_t*me, void** pkey, int* plen,void ** pdata,int *pdatalen)
{
	int ret = -1;
	DBM* db = (DBM*)me->db;
	dbpair ikey = {0};
	dbpair idata = {0};

	if (db == 0)
		return EDBL_PARAM;

	ikey = dbsm_firstkey(db);
	if (NULLITEM(ikey)) {
		ret = EDBL_FIND;
		goto __clean;
	}

	idata = dbsm_fetch(db, ikey);
	if (NULLITEM(idata)) {
		ret = EDBL_FIND;
		goto __clean;
	}

	*pkey = (void*)ikey.dptr;
	*plen = ikey.dsize;
	*pdata = (void*)idata.dptr;
	*pdatalen = idata.dsize;

	ret = EDBL_OK;
__clean:
	return ret;
}

int dblock_nextkey(dblock_t*me, void** pkey, int* plen,void ** pdata,int *pdatalen)
{
	int ret = -1;
	DBM* db = (DBM*)me->db;
	dbpair ikey = {0};
	dbpair idata = {0};

	if (db == 0)
		return EDBL_PARAM;

	ikey = dbsm_nextkey(db);
	if (NULLITEM(ikey)) {
		ret = EDBL_FIND;
		goto __clean;
	}

	idata = dbsm_fetch(db, ikey);
	if (NULLITEM(idata)) {
		ret = EDBL_FIND;
		goto __clean;
	}

	*pkey = (void*)ikey.dptr;
	*plen = ikey.dsize;
	*pdata = (void*)idata.dptr;
	*pdatalen = idata.dsize;

	ret = EDBL_OK;
__clean:
	return ret;
}

int dblock_closecursor(dblock_t*me)
{
	return EDBL_OK;
}
